home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DKBSRC.ARJ / TOKENIZE.C < prev    next >
C/C++ Source or Header  |  1991-05-07  |  22KB  |  800 lines

  1. /*****************************************************************************
  2. *
  3. *                                     tokenize.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module implements the first part of a two part parser for the scene
  8. *  description files.  This phase changes the input file into tokens.
  9. *
  10. * This software is freely distributable. The source and/or object code may be
  11. * copied or uploaded to communications services so long as this notice remains
  12. * at the top of each file.  If any changes are made to the program, you must
  13. * clearly indicate in the documentation and in the programs startup message
  14. * who it was who made the changes. The documentation should also describe what
  15. * those changes were. This software may not be included in whole or in
  16. * part into any commercial package without the express written consent of the
  17. * author.  It may, however, be included in other public domain or freely
  18. * distributed software so long as the proper credit for the software is given.
  19. *
  20. * This software is provided as is without any guarantees or warranty. Although
  21. * the author has attempted to find and correct any bugs in the software, he
  22. * is not responsible for any damage caused by the use of the software.  The
  23. * author is under no obligation to provide service, corrections, or upgrades
  24. * to this package.
  25. *
  26. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  27. * about them.  Also, if you have any comments or questions, you may contact me
  28. * at the following address:
  29. *
  30. *     David Buck
  31. *     22C Sonnet Cres.
  32. *     Nepean Ontario
  33. *     Canada, K2H 8W7
  34. *
  35. *  I can also be reached on the following bulleton boards:
  36. *
  37. *     OMX              (613) 731-3419
  38. *     Mystic           (613) 596-4249  or  (613) 596-4772
  39. *
  40. *  Fidonet:   1:163/109.9
  41. *  Internet:  dbuck@ccs.carleton.ca
  42. *  The "You Can Call Me RAY" BBS    (708) 358-5611
  43. *
  44. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  45. *
  46. *     The "You Can Call Me RAY" BBS (708) 358-5611
  47. *     The Information Exchange BBS  (708) 945-5575
  48. *
  49. *****************************************************************************/
  50.  
  51. #include <ctype.h>
  52. #include "frame.h"
  53. #include "dkbproto.h"
  54.  
  55. /* This module tokenizes the input file and sends the tokens created
  56. to the parser (the second stage).  Tokens sent to the parser contain a
  57. token ID, the line number of the token, and if necessary, some data for
  58. the token.  */
  59.  
  60. #define MAX_STRING_INDEX 41
  61. char String[MAX_STRING_INDEX];
  62. int String_Index;
  63. extern char Library_Path[];
  64.  
  65. /* Here are the reserved words.  If you need to add new words, be sure
  66. to declare them in frame.h */
  67.  
  68. struct Reserved_Word_Struct Reserved_Words [LAST_TOKEN] = {
  69. AGATE_TOKEN, "AGATE",
  70. ALL_TOKEN, "ALL",
  71. ALPHA_TOKEN, "ALPHA",
  72. AMBIENT_TOKEN, "AMBIENT",
  73. AMPERSAND_TOKEN, "&",
  74. AT_TOKEN, "@",
  75. BACK_QUOTE_TOKEN, "`",
  76. BACK_SLASH_TOKEN, "\\",
  77. BAR_TOKEN, "|",
  78. BLUE_TOKEN, "BLUE",
  79. BRILLIANCE_TOKEN, "BRILLIANCE",
  80. BOZO_TOKEN, "BOZO",
  81. BOUNDED_TOKEN, "BOUNDED_BY",
  82. BUMPS_TOKEN, "BUMPS",
  83. CHECKER_TOKEN, "CHECKER",
  84. CHECKER_TEXTURE_TOKEN, "CHECKER_TEXTURE",
  85. COLON_TOKEN, ":",
  86. COLOUR_TOKEN, "COLOR",
  87. COLOUR_TOKEN, "COLOUR",
  88. COLOUR_MAP_TOKEN, "COLOR_MAP",
  89. COLOUR_MAP_TOKEN, "COLOUR_MAP",
  90. COMMA_TOKEN, ",",
  91. COMPOSITE_TOKEN, "COMPOSITE",
  92. CONCENTRATION_TOKEN, "CONCENTRATION",
  93. DASH_TOKEN, "-",
  94. DECLARE_TOKEN, "DECLARE",
  95. DENTS_TOKEN, "DENTS",
  96. DIFFERENCE_TOKEN, "DIFFERENCE",
  97. DIFFUSE_TOKEN, "DIFFUSE",
  98. DIRECTION_TOKEN, "DIRECTION",
  99. DOLLAR_TOKEN, "$",
  100. DUMP_TOKEN, "DUMP",
  101. END_BOUNDED_TOKEN, "END_BOUND",
  102. END_CHECKER_TEXTURE_TOKEN, "END_CHECKER_TEXTURE",
  103. END_COLOUR_MAP_TOKEN, "END_COLOR_MAP",
  104. END_COLOUR_MAP_TOKEN, "END_COLOUR_MAP",
  105. END_COMPOSITE_TOKEN, "END_COMPOSITE",
  106. END_DIFFERENCE_TOKEN, "END_DIFFERENCE",
  107. END_FOG_TOKEN, "END_FOG",
  108. END_INTERSECTION_TOKEN, "END_INTERSECTION",
  109. END_OBJECT_TOKEN, "END_OBJECT",
  110. END_OF_FILE_TOKEN, "End of File",
  111. END_PLANE_TOKEN, "END_PLANE",
  112. END_POINTS_TOKEN, "END_POINTS",
  113. END_POLYGON_TOKEN, "END_POLYGON",
  114. END_QUADRIC_TOKEN, "END_QUADRIC",
  115. END_QUARTIC_TOKEN, "END_QUARTIC",
  116. END_SHAPE_TOKEN, "END_SHAPE",
  117. END_SMOOTH_TRIANGLE_TOKEN, "END_SMOOTH_TRIANGLE",
  118. END_SPHERE_TOKEN, "END_SPHERE",
  119. END_TEXTURE_TOKEN, "END_TEXTURE",
  120. END_TRIANGLE_TOKEN, "END_TRIANGLE",
  121. END_UNION_TOKEN, "END_UNION",
  122. END_VIEW_POINT_TOKEN, "END_VIEW_POINT",
  123. EQUALS_TOKEN, "=",
  124. EXCLAMATION_TOKEN, "!",
  125. FLOAT_TOKEN, "FLOAT",
  126. FOG_TOKEN, "FOG",
  127. FREQUENCY_TOKEN, "FREQUENCY",
  128. GIF_TOKEN, "GIF",
  129. GRANITE_TOKEN, "GRANITE",
  130. GRADIENT_TOKEN, "GRADIENT",
  131. GREEN_TOKEN, "GREEN",
  132. HASH_TOKEN, "#",
  133. HAT_TOKEN, "^",
  134. IDENTIFIER_TOKEN, "IDENTIFIER",
  135. IFF_TOKEN, "IFF",
  136. IMAGEMAP_TOKEN, "IMAGEMAP",
  137. INCLUDE_TOKEN, "INCLUDE",
  138. INTERSECTION_TOKEN, "INTERSECTION",
  139. INVERSE_TOKEN, "INVERSE",
  140. IOR_TOKEN, "IOR",
  141. LEFT_ANGLE_TOKEN, "<",
  142. LEFT_BRACKET_TOKEN, "{",
  143. LEFT_SQUARE_TOKEN, "[",
  144. LIGHT_SOURCE_TOKEN, "LIGHT_SOURCE",
  145. LOCATION_TOKEN, "LOCATION",
  146. LOOK_AT_TOKEN, "LOOK_AT",
  147. MARBLE_TOKEN, "MARBLE",
  148. METALLIC_TOKEN, "METALLIC",
  149. OBJECT_TOKEN, "OBJECT",
  150. ONCE_TOKEN, "ONCE",
  151. PERCENT_TOKEN, "%",
  152. PHASE_TOKEN, "PHASE",
  153. PHONG_TOKEN, "PHONG",
  154. PHONGSIZE_TOKEN, "PHONGSIZE",
  155. PLANE_TOKEN, "PLANE",
  156. PLUS_TOKEN, "+",
  157. POINTS_TOKEN, "POINTS",
  158. POINT_AT_TOKEN, "POINT_AT",
  159. POLYGON_TOKEN, "POLYGON",
  160. QUADRIC_TOKEN, "QUADRIC",
  161. QUARTIC_TOKEN, "QUARTIC",
  162. QUESTION_TOKEN, "?",
  163. RAW_TOKEN, "RAW",
  164. RED_TOKEN, "RED",
  165. REFLECTION_TOKEN, "REFLECTION",
  166. REFRACTION_TOKEN, "REFRACTION",
  167. REVOLVE_TOKEN, "REVOLVE",
  168. RIGHT_TOKEN, "RIGHT",
  169. RIGHT_ANGLE_TOKEN, ">",
  170. RIGHT_BRACKET_TOKEN, ")",
  171. RIGHT_SQUARE_TOKEN, "]",
  172. RIPPLES_TOKEN, "RIPPLES",
  173. ROTATE_TOKEN, "ROTATE",
  174. ROUGHNESS_TOKEN, "ROUGHNESS",
  175. SCALE_TOKEN, "SCALE",
  176. SEMI_COLON_TOKEN, ";",
  177. SHAPE_TOKEN, "SHAPE",
  178. SKY_TOKEN, "SKY",
  179. SINGLE_QUOTE_TOKEN, "'",
  180. SIZE_TOKEN, "SIZE",
  181. SLASH_TOKEN, "/",
  182. SMOOTH_TRIANGLE_TOKEN, "SMOOTH_TRIANGLE",
  183. SPECULAR_TOKEN, "SPECULAR",
  184. SPHERE_TOKEN, "SPHERE",
  185. SPOTLIGHT_TOKEN, "SPOTLIGHT",
  186. SPOTTED_TOKEN, "SPOTTED",
  187. STAR_TOKEN, "*",
  188. STRING_TOKEN, "STRING",
  189. TEXTURE_TOKEN, "TEXTURE",
  190. TILDE_TOKEN, "~",
  191. TILE2_TOKEN, "TILE2",
  192. TRANSLATE_TOKEN, "TRANSLATE",
  193. TRIANGLE_TOKEN, "TRIANGLE",
  194. TURBULENCE_TOKEN, "TURBULENCE",
  195. UNION_TOKEN, "UNION",
  196. UP_TOKEN, "UP",
  197. VIEW_POINT_TOKEN, "VIEW_POINT",
  198. WAVES_TOKEN, "WAVES",
  199. WOOD_TOKEN, "WOOD",
  200. WRINKLES_TOKEN, "WRINKLES"
  201.   };
  202.  
  203. /* Make a table for user-defined symbols.  500 symbols should be more
  204. than enough. */
  205.  
  206. #define MAX_SYMBOLS 500
  207.  
  208. char **Symbol_Table;
  209. int Number_Of_Symbols;
  210.  
  211. #define MAX_INCLUDE_FILES 10
  212.  
  213. DATA_FILE Include_Files[MAX_INCLUDE_FILES];
  214. int Include_File_Index;
  215. DATA_FILE *Data_File;
  216.  
  217. struct Token_Struct Token;
  218.  
  219. #define CALL(x) { if (!(x)) return (FALSE); }
  220.  
  221. void Initialize_Tokenizer(filename)
  222.    char *filename;
  223.    {
  224.    Symbol_Table = NULL;
  225.    Data_File = NULL;
  226.  
  227.    Include_File_Index = 0;
  228.    Data_File = &Include_Files[0];
  229.  
  230.    Data_File->File = Locate_File (filename, "r");
  231.    if (Data_File->File == NULL) {
  232.       fprintf (stderr, "Cannot open input file\n");
  233.       exit(1);
  234.       }
  235.  
  236.    Data_File->Filename = malloc(strlen(filename) + 1);
  237.    strcpy (Data_File->Filename, filename);
  238.    Data_File->Line_Number = 0;
  239.  
  240.  
  241.    if ((Symbol_Table = (char **) malloc (MAX_SYMBOLS * sizeof (char *))) == NULL) {
  242.       fprintf(stderr, "Cannot allocate space for symbol table\n");
  243.       exit(1);
  244.       }
  245.  
  246.    Token.End_Of_File = FALSE;
  247.    Number_Of_Symbols = 0;
  248.    }
  249.  
  250.  
  251. void Terminate_Tokenizer()
  252.    {
  253.    int i;
  254.  
  255.    if (Symbol_Table != NULL) {
  256.       for (i = 1 ; i < Number_Of_Symbols ; i++)
  257.          free(Symbol_Table[i]);
  258.  
  259.       free (Symbol_Table);
  260.       }
  261.  
  262.    if (Data_File != NULL) {
  263.       fclose (Data_File->File);
  264.       free (Data_File->Filename);
  265.       }
  266.    }
  267.  
  268. /* The main tokenizing routine.  Set up the files and continue parsing
  269. until the end of file */
  270.  
  271. /* This function performs most of the work involved in tokenizing.  It
  272.    reads the first character of the token and decides which function to
  273.    call to tokenize the rest.  For simple tokens, it simply writes them
  274.    out to the token buffer.  */
  275.  
  276. /* Read a token from the input file and store it in the Token variable.
  277. If the token is an INCLUDE token, then set the include file name and
  278. read another token. */
  279.  
  280. void Get_Token ()
  281.   {
  282.   register int c;
  283.   static int token_count = 0, line_count = 0;
  284.  
  285.   if (Token.Unget_Token)
  286.     {
  287.     Token.Unget_Token = FALSE;
  288.     return;
  289.     }
  290.  
  291.   if (Token.End_Of_File)
  292.     return;
  293.  
  294.   Token.Token_Id = END_OF_FILE_TOKEN;
  295.  
  296.   while (Token.Token_Id == END_OF_FILE_TOKEN) {
  297.  
  298.      Skip_Spaces (Data_File);
  299.    
  300.      c = getc(Data_File->File);
  301.      if (c == EOF) {
  302.        if (Include_File_Index == 0) {
  303.           Token.Token_Id = END_OF_FILE_TOKEN;
  304.           Token.End_Of_File = TRUE;
  305.           putchar ('\n');
  306.           return;
  307.           }
  308.  
  309.        Data_File = &Include_Files[--Include_File_Index];
  310.        continue;
  311.        }
  312.    
  313.      String[0] = '\0';
  314.      String_Index  = 0;
  315.    
  316.      switch (c)
  317.        {
  318.        case '\n': Data_File->Line_Number++;
  319.                   break;
  320.    
  321.        case '{' : Parse_Comments(Data_File);
  322.                   break;
  323.    
  324.        case '@' : Write_Token (AT_TOKEN, Data_File);
  325.                   break;
  326.    
  327.        case '&' : Write_Token (AMPERSAND_TOKEN, Data_File);
  328.                   break;
  329.    
  330.        case '`' : Write_Token (BACK_QUOTE_TOKEN, Data_File);
  331.                   break;
  332.    
  333.        case '\\': Write_Token (BACK_SLASH_TOKEN, Data_File);
  334.                   break;
  335.    
  336.        case '|' : Write_Token (BAR_TOKEN, Data_File);
  337.                   break;
  338.    
  339.        case ':' : Write_Token (COLON_TOKEN, Data_File);
  340.                   break;
  341.    
  342.        case ',' : Write_Token (COMMA_TOKEN, Data_File);
  343.                   break;
  344.    
  345.        case '-' : Write_Token (DASH_TOKEN, Data_File);
  346.                   break;
  347.    
  348.        case '$' : Write_Token (DOLLAR_TOKEN, Data_File);
  349.                   break;
  350.    
  351.        case '=' : Write_Token (EQUALS_TOKEN, Data_File);
  352.                   break;
  353.    
  354.        case '!' : Write_Token (EXCLAMATION_TOKEN, Data_File);
  355.                   break;
  356.    
  357.        case '#' : Write_Token (HASH_TOKEN, Data_File);
  358.                   break;
  359.    
  360.        case '^' : Write_Token (HAT_TOKEN, Data_File);
  361.                   break;
  362.    
  363.        case '<' : Write_Token (LEFT_ANGLE_TOKEN, Data_File);
  364.                   break;
  365.    
  366.        case '(' : Write_Token (LEFT_BRACKET_TOKEN, Data_File);
  367.                   break;
  368.    
  369.        case '[' : Write_Token (LEFT_SQUARE_TOKEN, Data_File);
  370.                   break;
  371.    
  372.        case '%' :  Write_Token (PERCENT_TOKEN, Data_File);
  373.                   break;
  374.    
  375.        case '+' : Write_Token (PLUS_TOKEN, Data_File);
  376.                   break;
  377.    
  378.        case '?' : Write_Token (QUESTION_TOKEN, Data_File);
  379.                   break;
  380.    
  381.        case '>' : Write_Token (RIGHT_ANGLE_TOKEN, Data_File);
  382.                   break;
  383.    
  384.        case ')' : Write_Token (RIGHT_BRACKET_TOKEN, Data_File);
  385.                   break;
  386.    
  387.        case ']' : Write_Token (RIGHT_SQUARE_TOKEN, Data_File);
  388.                   break;
  389.    
  390.        case ';' : Write_Token (SEMI_COLON_TOKEN, Data_File);
  391.                   break;
  392.    
  393.        case '\'': Write_Token (SINGLE_QUOTE_TOKEN, Data_File);
  394.                   break;
  395.    
  396.        case '/' : Write_Token (SLASH_TOKEN, Data_File);
  397.                   break;
  398.    
  399.        case '*' : Write_Token (STAR_TOKEN, Data_File);
  400.                   break;
  401.    
  402.        case '~' : Write_Token (TILDE_TOKEN, Data_File);
  403.                   break;
  404.    
  405.        case '"' : Parse_String (Data_File);
  406.                   break;
  407.    
  408.        case '0':   case '1':   case '2':   case '3':   case '4':   case '5':
  409.        case '6':   case '7':   case '8':   case '9':
  410.                   ungetc (c, Data_File->File);
  411.                   if (Read_Float (Data_File) != TRUE)
  412.                      return;
  413.                   break;
  414.    
  415.        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
  416.        case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
  417.        case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
  418.        case 'v': case 'w': case 'x': case 'y': case 'z':
  419.        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
  420.        case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
  421.        case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
  422.        case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_':
  423.                   ungetc (c, Data_File->File);
  424.                   if (Read_Symbol (Data_File) != TRUE)
  425.                      return;
  426.                   break;
  427.  
  428.        case '\r':
  429.        case '\032':   /* Control Z - EOF on many systems */
  430.        case '\0': break;
  431.  
  432.        default:
  433.          fprintf (stderr, "Error in %s line %d\n", Data_File->Filename, Data_File->Line_Number);
  434.          fprintf (stderr, "Illegal character in input file, value is %02x\n", c);
  435.          break;
  436.        }
  437.  
  438.     if (Token.Token_Id == INCLUDE_TOKEN)
  439.        {
  440.        if (Skip_Spaces (Data_File) != TRUE)
  441.           Token_Error (Data_File, "Expecting a string after INCLUDE\n");
  442.  
  443.        if ((c = getc(Data_File->File)) != '"')
  444.           Token_Error (Data_File, "Expecting a string after INCLUDE\n");
  445.  
  446.        Parse_String(Data_File);
  447.        Include_File_Index++;
  448.        if (Include_File_Index > MAX_INCLUDE_FILES)
  449.           Token_Error (Data_File, "Too many nested include files\n");
  450.  
  451.        Data_File = &Include_Files[Include_File_Index];
  452.        Data_File->Line_Number = 0;
  453.  
  454.        Data_File->Filename = malloc(strlen(Token.Token_String) + 1);
  455.        if (Data_File->Filename == NULL) {
  456.           fprintf (stderr, "Out of memory opening include file: %s\n",
  457.                    Token.Token_String);
  458.           exit (1);
  459.           }
  460.  
  461.        strcpy (Data_File->Filename, Token.Token_String);
  462.  
  463.        if ((Data_File->File = Locate_File (Token.Token_String, "r")) == NULL) {
  464.           fprintf (stderr, "Cannot open include file: %s\n", Token.Token_String);
  465.           exit(1);
  466.           }
  467.        Token.Token_Id = END_OF_FILE_TOKEN;
  468.        }
  469.  
  470.     }
  471.  
  472.   token_count++;
  473.   if (token_count > 1000) {
  474.     token_count = 0;
  475.     putchar('.');
  476.     fflush(stdout);
  477.     line_count++;
  478.     if (line_count > 78) {
  479.        line_count = 0;
  480.        putchar ('\n');
  481.        }
  482.     }
  483.   return;
  484.   }
  485.  
  486.  
  487. /* Mark that the token has been put back into the input stream.  The next
  488. call to Get_Token will return the last-read token instead of reading a
  489. new one from the file. */
  490.  
  491. void Unget_Token ()
  492.   {
  493.   Token.Unget_Token = TRUE;
  494.   }
  495.  
  496. /* Skip over spaces in the input file */
  497.  
  498. int Skip_Spaces (Data_File)
  499.   DATA_FILE *Data_File;
  500.   {
  501.   register int c;
  502.  
  503.   while (TRUE)
  504.     {
  505.     c = getc(Data_File->File);
  506.     if (c == EOF)
  507.       return (FALSE);
  508.  
  509.     if (!(isspace(c) || c == 0x0A))
  510.       break;
  511.  
  512.     if (c == '\n')
  513.        Data_File->Line_Number++;
  514.     }
  515.  
  516.   ungetc (c, Data_File->File);
  517.   return (TRUE);
  518.   }
  519.  
  520. /* Comments start with an open brace ({) and end with a close brace (}).
  521.    The open brace has been read already.  Continue reading until a close
  522.    brace is encountered. Be sure to count the lines while you're at it.
  523.    Incidently, nested comments are supported (in case you do such esoteric
  524.    things) */
  525.  
  526. int Parse_Comments (Data_File)
  527.   DATA_FILE *Data_File;
  528.   {
  529.   register int c;
  530.   int End_Of_Comment;
  531.   
  532.   End_Of_Comment = FALSE;
  533.   while (!End_Of_Comment)
  534.     {
  535.     c = getc (Data_File->File);
  536.     if (c == EOF)
  537.       {
  538.       Token_Error (Data_File, "No closing comment found");
  539.       return (FALSE);
  540.       }
  541.  
  542.     if (c == (int) '\n')
  543.       Data_File->Line_Number++;
  544.  
  545.     if (c == (int) '{')
  546.       CALL (Parse_Comments(Data_File))
  547.     else
  548.       End_Of_Comment = (c == (int) '}');
  549.     }
  550.  
  551.   return (TRUE);
  552.   }
  553.  
  554. /* The following routines make it easier to handle strings.  They stuff
  555.    characters into a string buffer one at a time making all the proper
  556.    range checks.  Call Begin_String to start, Stuff_Character to put
  557.    characters in, and End_String to finish.  The String variable contains
  558.    the final string. */
  559.  
  560. void Begin_String()
  561.   {
  562.   String_Index = 0;
  563.   }
  564.  
  565. void Stuff_Character (c, Data_File)
  566.   int c;
  567.   DATA_FILE *Data_File;
  568.   {
  569.   if (String_Index < MAX_STRING_INDEX)
  570.     {
  571.     String [String_Index++] = (char) c;
  572.     if (String_Index >= MAX_STRING_INDEX)
  573.       {
  574.       Token_Error (Data_File, "String too long");
  575.       String [String_Index-1] = '\0';
  576.       }
  577.     }
  578.   }
  579.  
  580. void End_String (Data_File)
  581.   DATA_FILE *Data_File;
  582.   {
  583.   Stuff_Character ((int) '\0', Data_File);
  584.   }
  585.  
  586. /* Read a float from the input file and tokenize it as one token. The phase
  587.    variable is 0 for the first character, 1 for all subsequent characters
  588.    up to the decimal point, and 2 for all characters after the decimal
  589.    point.  This helps to insure that the number is formatted properly. */
  590.  
  591. int Read_Float(Data_File)
  592.   DATA_FILE *Data_File;
  593.   {
  594.   register int c, Finished, Phase;
  595.  
  596.   Finished = FALSE;
  597.   Phase = 0;
  598.  
  599.   Begin_String();
  600.   while (!Finished)
  601.     {
  602.     c = getc(Data_File->File);
  603.     if (c == EOF)
  604.       {
  605.       Token_Error (Data_File, "Unexpected end of file");
  606.       return (FALSE);
  607.       }
  608.  
  609.     switch (Phase)
  610.       {
  611.       case 0: if (isdigit(c))
  612.                 Stuff_Character(c, Data_File);
  613.               else
  614.                 if (c == '.') {
  615.                    Stuff_Character('0', Data_File);
  616.                    ungetc (c, Data_File->File);
  617.                    }
  618.                 else
  619.                    Token_Error (Data_File, "Error in decimal number");
  620.               Phase = 1;
  621.               break;
  622.      
  623.       case 1: if (isdigit(c))
  624.                 Stuff_Character(c, Data_File);
  625.               else if (c == (int) '.')
  626.                 {
  627.                 Stuff_Character(c, Data_File);
  628.                 Phase = 2;
  629.                 }
  630.               else if ((c == 'e') || (c == 'E')) {
  631.                 Stuff_Character(c, Data_File);
  632.                 Phase = 3;
  633.                 }
  634.               else
  635.                 Finished = TRUE;
  636.               break;
  637.  
  638.       case 2: if (isdigit(c))
  639.                 Stuff_Character(c, Data_File);
  640.               else if ((c == 'e') || (c == 'E')) {
  641.                 Stuff_Character(c, Data_File);
  642.                 Phase = 3;
  643.                 }
  644.               else
  645.                 Finished = TRUE;
  646.               break;
  647.  
  648.       case 3: if (isdigit(c) || (c == '-'))
  649.                 Stuff_Character(c, Data_File);
  650.               else
  651.                 Finished = TRUE;
  652.       }
  653.     }
  654.  
  655.   ungetc (c, Data_File->File);
  656.   End_String(Data_File);
  657.  
  658.   Write_Token (FLOAT_TOKEN, Data_File);
  659.   sscanf (String, DBL_FORMAT_STRING, &Token.Token_Float);
  660.  
  661.   return (TRUE);
  662.   }
  663.  
  664. /* Parse a string from the input file into a token. */
  665. void Parse_String (Data_File)
  666.   DATA_FILE *Data_File;
  667.   {
  668.   register int c;
  669.  
  670.   Begin_String();
  671.   while (TRUE)
  672.     {
  673.     c = getc(Data_File->File);
  674.     if (c == EOF)
  675.       Token_Error (Data_File, "No end quote for string");
  676.  
  677.     if (c != (int) '"')
  678.       Stuff_Character (c, Data_File);
  679.     else
  680.       break;
  681.     }
  682.   End_String(Data_File);
  683.  
  684.   Write_Token (STRING_TOKEN, Data_File);
  685.   Token.Token_String = String;
  686.   }
  687.  
  688. /* Read    in a symbol from the input file.  Check to see if it is a reserved
  689.    word.  If it is, write out the appropriate token.  Otherwise, write the
  690.    symbol out to the Symbol file and write out an IDENTIFIER token. An
  691.    Identifier token is a token whose token number is greater than the
  692.    highest reserved word. */
  693.  
  694. int Read_Symbol (Data_File)
  695.   DATA_FILE *Data_File;
  696.   {
  697.   register int c, Symbol_Id;
  698.  
  699.   Begin_String();
  700.   while (TRUE)
  701.     {
  702.     c = getc(Data_File->File);
  703.     if (c == EOF)
  704.       {
  705.       Token_Error (Data_File, "Unexpected end of file");
  706.       return (FALSE);
  707.       }
  708.  
  709.     if (isalpha(c) || isdigit(c) || c == (int) '_')
  710.       Stuff_Character (c, Data_File);
  711.     else
  712.       {
  713.       ungetc (c, Data_File->File);
  714.       break;
  715.       }
  716.     }
  717.   End_String(Data_File);
  718.  
  719.   if ((Symbol_Id = Find_Reserved()) != -1)
  720.      Write_Token (Symbol_Id, Data_File);
  721.   else
  722.     {
  723.     if ((Symbol_Id = Find_Symbol()) == -1)
  724.       if (++Number_Of_Symbols < MAX_SYMBOLS)
  725.         {
  726.         if ((Symbol_Table[Number_Of_Symbols] = malloc (strlen(String)+1)) == NULL)
  727.            Token_Error (Data_File, "Cannot allocate space for identifier");
  728.  
  729.         strcpy (Symbol_Table[Number_Of_Symbols], String);
  730.         Symbol_Id = Number_Of_Symbols;
  731.         }
  732.       else
  733.         {
  734.         fprintf (stderr, "\nToo many symbols\n");
  735.         exit(1);
  736.         }
  737.  
  738.     Write_Token (LAST_TOKEN + Symbol_Id, Data_File);
  739.     }
  740.  
  741.   return (TRUE);
  742.   }
  743.  
  744. /* Return the index the token in the reserved words table or -1 if it
  745.    isn't there. */
  746.  
  747. int Find_Reserved ()
  748.   {
  749.   register int i;
  750.  
  751.   for (i = 0 ; i < LAST_TOKEN ; i++)
  752.     if (strcmp (Reserved_Words[i].Token_Name, &(String[0])) == 0)
  753.       return (Reserved_Words[i].Token_Number);
  754.  
  755.   return (-1);
  756.   }
  757.  
  758. /* Check to see if a symbol already exists with this name.  If so, return
  759.     its symbol ID. */
  760.  
  761. int Find_Symbol ()
  762.   {
  763.   register int i;
  764.  
  765.   for (i = 1 ; i <= Number_Of_Symbols ; i++)
  766.     if (strcmp (Symbol_Table[i], String) == 0)
  767.       return (i);
  768.  
  769.   return (-1);
  770.   }
  771.  
  772. /* Write a token out to the token file */
  773. void Write_Token (Token_Id, Data_File)
  774.   TOKEN Token_Id;
  775.   DATA_FILE *Data_File;
  776.   {
  777.   Token.Token_Id = Token_Id;
  778.   Token.Token_Line_No = Data_File->Line_Number;
  779.   Token.Filename = Data_File->Filename;
  780.   Token.Token_String = String;
  781.  
  782.   if (Token.Token_Id > LAST_TOKEN)
  783.     {
  784.     Token.Identifier_Number = (int) Token.Token_Id - (int) LAST_TOKEN;
  785.     Token.Token_Id = IDENTIFIER_TOKEN;
  786.     }
  787.   }
  788.  
  789. /* Report an error */
  790. void Token_Error (Data_File, str)
  791.   DATA_FILE *Data_File;
  792.   char *str;
  793.   {
  794.   fprintf(stderr, "Error in %s line %d\n", Data_File->Filename, Data_File->Line_Number);
  795.   fputs(str, stderr);
  796.   fputs("\n\n", stderr);
  797.   exit(1);
  798.   }
  799.  
  800.